EMMA Coverage Report (generated Mon Sep 05 20:29:20 CEST 2016)
[all classes][net.mandaria.tippytipper.widgets]

COVERAGE SUMMARY FOR SOURCE FILE [NumberPicker.java]

nameclass, %method, %block, %line, %
NumberPicker.java100% (6/6)93%  (43/46)80%  (666/828)84%  (145/173)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class NumberPicker$NumberPickerInputFilter100% (1/1)100% (3/3)30%  (25/83)25%  (3/12)
filter (CharSequence, int, int, Spanned, int, int): CharSequence 100% (1/1)21%  (15/73)18%  (2/11)
NumberPicker$NumberPickerInputFilter (NumberPicker): void 100% (1/1)100% (6/6)100% (1/1)
NumberPicker$NumberPickerInputFilter (NumberPicker, NumberPicker$1): void 100% (1/1)100% (4/4)100% (1/1)
     
class NumberPicker$1100% (1/1)50%  (1/2)43%  (19/44)50%  (4/8)
toString (int): String 0%   (0/1)0%   (0/25)0%   (0/4)
NumberPicker$1 (): void 100% (1/1)100% (19/19)100% (4/4)
     
class NumberPicker100% (1/1)97%  (31/32)86%  (461/538)89%  (110/124)
setOnChangeListener (NumberPicker$OnChangedListener): void 0%   (0/1)0%   (0/4)0%   (0/2)
getSelectedPos (String): int 100% (1/1)16%  (6/38)22%  (2/9)
notifyChange (): void 100% (1/1)33%  (4/12)67%  (2/3)
validateInput (View): void 100% (1/1)63%  (32/51)78%  (7/9)
updateView (): void 100% (1/1)63%  (19/30)80%  (4/5)
NumberPicker (Context, AttributeSet, int): void 100% (1/1)97%  (114/117)96%  (25/26)
<static initializer> 100% (1/1)100% (52/52)100% (3/3)
NumberPicker (Context): void 100% (1/1)100% (5/5)100% (2/2)
NumberPicker (Context, AttributeSet): void 100% (1/1)100% (6/6)100% (2/2)
access$000 (NumberPicker): boolean 100% (1/1)100% (3/3)100% (1/1)
access$100 (NumberPicker): long 100% (1/1)100% (3/3)100% (1/1)
access$200 (NumberPicker): Handler 100% (1/1)100% (3/3)100% (1/1)
access$300 (NumberPicker): boolean 100% (1/1)100% (3/3)100% (1/1)
access$600 (NumberPicker): String [] 100% (1/1)100% (3/3)100% (1/1)
access$700 (NumberPicker): InputFilter 100% (1/1)100% (3/3)100% (1/1)
access$800 (): char [] 100% (1/1)100% (2/2)100% (1/1)
access$900 (NumberPicker, String): int 100% (1/1)100% (4/4)100% (1/1)
cancelDecrement (): void 100% (1/1)100% (4/4)100% (2/2)
cancelIncrement (): void 100% (1/1)100% (4/4)100% (2/2)
changeCurrent (int): void 100% (1/1)100% (27/27)100% (9/9)
formatNumber (int): String 100% (1/1)100% (11/11)100% (3/3)
getCurrent (): int 100% (1/1)100% (3/3)100% (1/1)
getCurrentFormatted (): String 100% (1/1)100% (5/5)100% (1/1)
onClick (View): void 100% (1/1)100% (36/36)100% (8/8)
onFocusChange (View, boolean): void 100% (1/1)100% (6/6)100% (3/3)
onLongClick (View): boolean 100% (1/1)100% (32/32)100% (8/8)
setCurrent (int): void 100% (1/1)100% (6/6)100% (3/3)
setEnabled (boolean): void 100% (1/1)100% (16/16)100% (5/5)
setFormatter (NumberPicker$Formatter): void 100% (1/1)100% (4/4)100% (2/2)
setRange (int, int): void 100% (1/1)100% (12/12)100% (5/5)
setSpeed (long): void 100% (1/1)100% (4/4)100% (2/2)
validateCurrentView (CharSequence): void 100% (1/1)100% (29/29)100% (8/8)
     
class NumberPicker$NumberRangeKeyListener100% (1/1)80%  (4/5)97%  (67/69)93%  (13/14)
getInputType (): int 0%   (0/1)0%   (0/2)0%   (0/1)
NumberPicker$NumberRangeKeyListener (NumberPicker): void 100% (1/1)100% (6/6)100% (1/1)
NumberPicker$NumberRangeKeyListener (NumberPicker, NumberPicker$1): void 100% (1/1)100% (4/4)100% (1/1)
filter (CharSequence, int, int, Spanned, int, int): CharSequence 100% (1/1)100% (55/55)100% (11/11)
getAcceptedChars (): char [] 100% (1/1)100% (2/2)100% (1/1)
     
class NumberPicker$2100% (1/1)100% (2/2)100% (44/44)100% (8/8)
NumberPicker$2 (): void 100% (1/1)100% (19/19)100% (4/4)
toString (int): String 100% (1/1)100% (25/25)100% (4/4)
     
class NumberPicker$3100% (1/1)100% (2/2)100% (50/50)100% (8/8)
NumberPicker$3 (NumberPicker): void 100% (1/1)100% (6/6)100% (1/1)
run (): void 100% (1/1)100% (44/44)100% (7/7)

1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 
17package net.mandaria.tippytipper.widgets;
18 
19import net.mandaria.tippytipper.R;
20import android.annotation.SuppressLint;
21import android.content.Context;
22import android.os.Handler;
23import android.text.InputFilter;
24import android.text.InputType;
25import android.text.Spanned;
26import android.text.method.NumberKeyListener;
27import android.util.AttributeSet;
28import android.view.LayoutInflater;
29import android.view.View;
30import android.view.View.OnClickListener;
31import android.view.View.OnFocusChangeListener;
32import android.view.View.OnLongClickListener;
33import android.widget.TextView;
34import android.widget.LinearLayout;
35import android.widget.EditText;
36 
37/**
38 * This class has been pulled from the Android platform source code, its an internal widget that hasn't been
39 * made public so its included in the project in this fashion for use with the preferences screen; I have made
40 * a few slight modifications to the code here, I simply put a MAX and MIN default in the code but these values
41 * can still be set publically by calling code.
42 *
43 * @author Google
44 */
45public class NumberPicker extends LinearLayout implements OnClickListener,
46        OnFocusChangeListener, OnLongClickListener {
47 
48    private static final int DEFAULT_MAX = 999;
49    private static final int DEFAULT_MIN = 0;
50 
51    public interface OnChangedListener {
52        void onChanged(NumberPicker picker, int oldVal, int newVal);
53    }
54 
55    public interface Formatter {
56        String toString(int value);
57    }
58 
59    /*
60     * Use a custom NumberPicker formatting callback to use two-digit
61     * minutes strings like "01".  Keeping a static formatter etc. is the
62     * most efficient way to do this; it avoids creating temporary objects
63     * on every call to format().
64     */
65    public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER =
66            new NumberPicker.Formatter() {
67                final StringBuilder mBuilder = new StringBuilder();
68                final java.util.Formatter mFmt = new java.util.Formatter(mBuilder);
69                final Object[] mArgs = new Object[1];
70                public String toString(int value) {
71                    mArgs[0] = value;
72                    mBuilder.delete(0, mBuilder.length());
73                    mFmt.format("%02d", mArgs);
74                    return mFmt.toString();
75                }
76        };
77        
78    public static final NumberPicker.Formatter THREE_DIGIT_FORMATTER =
79            new NumberPicker.Formatter() {
80                final StringBuilder mBuilder = new StringBuilder();
81                final java.util.Formatter mFmt = new java.util.Formatter(mBuilder);
82                final Object[] mArgs = new Object[1];
83                public String toString(int value) {
84                    mArgs[0] = value;
85                    mBuilder.delete(0, mBuilder.length());
86                    mFmt.format("%03d", mArgs);
87                    return mFmt.toString();
88                }
89        };
90 
91    private final Handler mHandler;
92    private final Runnable mRunnable = new Runnable() {
93        public void run() {
94            if (mIncrement) {
95                changeCurrent(mCurrent + 1);
96                mHandler.postDelayed(this, mSpeed);
97            } else if (mDecrement) {
98                changeCurrent(mCurrent - 1);
99                mHandler.postDelayed(this, mSpeed);
100            }
101        }
102    };
103 
104    private final EditText mText;
105    private final InputFilter mNumberInputFilter;
106 
107    private String[] mDisplayedValues;
108    protected int mStart;
109    protected int mEnd;
110    protected int mCurrent;
111    protected int mPrevious;
112    private OnChangedListener mListener;
113    private Formatter mFormatter;
114    private long mSpeed = 300;
115 
116    private boolean mIncrement;
117    private boolean mDecrement;
118 
119    public NumberPicker(Context context) {
120        this(context, null);
121    }
122 
123    public NumberPicker(Context context, AttributeSet attrs) {
124        this(context, attrs, 0);
125    }
126 
127    @SuppressWarnings({})
128    public NumberPicker(Context context, AttributeSet attrs, int defStyle) {
129        super(context, attrs);
130        setOrientation(VERTICAL);
131        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
132        inflater.inflate(R.layout.number_picker, this, true);
133        mHandler = new Handler();
134        InputFilter inputFilter = new NumberPickerInputFilter();
135        mNumberInputFilter = new NumberRangeKeyListener();
136        mIncrementButton = (NumberPickerButton) findViewById(R.id.increment);
137        mIncrementButton.setOnClickListener(this);
138        mIncrementButton.setOnLongClickListener(this);
139        mIncrementButton.setNumberPicker(this);
140        mDecrementButton = (NumberPickerButton) findViewById(R.id.decrement);
141        mDecrementButton.setOnClickListener(this);
142        mDecrementButton.setOnLongClickListener(this);
143        mDecrementButton.setNumberPicker(this);
144 
145        mText = (EditText) findViewById(R.id.timepicker_input);
146        mText.setOnFocusChangeListener(this);
147        mText.setFilters(new InputFilter[] {inputFilter});
148        mText.setRawInputType(InputType.TYPE_CLASS_NUMBER);
149 
150        if (!isEnabled()) {
151            setEnabled(false);
152        }
153 
154        mStart = DEFAULT_MIN;
155        mEnd = DEFAULT_MAX;
156    }
157 
158    @Override
159    public void setEnabled(boolean enabled) {
160        super.setEnabled(enabled);
161        mIncrementButton.setEnabled(enabled);
162        mDecrementButton.setEnabled(enabled);
163        mText.setEnabled(enabled);
164    }
165 
166    public void setOnChangeListener(OnChangedListener listener) {
167        mListener = listener;
168    }
169 
170    public void setFormatter(Formatter formatter) {
171        mFormatter = formatter;
172    }
173 
174    /**
175     * Set the range of numbers allowed for the number picker. The current
176     * value will be automatically set to the start.
177     *
178     * @param start the start of the range (inclusive)
179     * @param end the end of the range (inclusive)
180     */
181    public void setRange(int start, int end) {
182        mStart = start;
183        mEnd = end;
184        mCurrent = start;
185        updateView();
186    }
187 
188    public void setCurrent(int current) {
189        mCurrent = current;
190        updateView();
191    }
192 
193    /**
194     * The speed (in milliseconds) at which the numbers will scroll
195     * when the the +/- buttons are longpressed. Default is 300ms.
196     */
197    public void setSpeed(long speed) {
198        mSpeed = speed;
199    }
200 
201    public void onClick(View v) {
202        validateInput(mText);
203        if (!mText.hasFocus()) mText.requestFocus();
204 
205        if(v != null)
206        {
207                // now perform the increment/decrement
208                if (R.id.increment == v.getId()) {
209                    changeCurrent(mCurrent + 1);
210                } else if (R.id.decrement == v.getId()) {
211                    changeCurrent(mCurrent - 1);
212                }
213        }
214    }
215 
216    private String formatNumber(int value) {
217        return (mFormatter != null)
218                ? mFormatter.toString(value)
219                : String.valueOf(value);
220    }
221 
222    protected void changeCurrent(int current) {
223 
224        // Wrap around the values if we go past the start or end
225        if (current > mEnd) {
226            current = mStart;
227        } else if (current < mStart) {
228            current = mEnd;
229        }
230        mPrevious = mCurrent;
231        mCurrent = current;
232 
233        notifyChange();
234        updateView();
235    }
236 
237    protected void notifyChange() {
238        if (mListener != null) {
239            mListener.onChanged(this, mPrevious, mCurrent);
240        }
241    }
242 
243    protected void updateView() {
244 
245        /* If we don't have displayed values then use the
246         * current number else find the correct value in the
247         * displayed values for the current number.
248         */
249        if (mDisplayedValues == null) {
250            mText.setText(formatNumber(mCurrent));
251        } else {
252            mText.setText(mDisplayedValues[mCurrent - mStart]);
253        }
254        mText.setSelection(mText.getText().length());
255    }
256 
257    private void validateCurrentView(CharSequence str) {
258        int val = getSelectedPos(str.toString());
259        if ((val >= mStart) && (val <= mEnd)) {
260            if (mCurrent != val) {
261                mPrevious = mCurrent;
262                mCurrent = val;
263                notifyChange();
264            }
265        }
266        updateView();
267    }
268 
269    public void onFocusChange(View v, boolean hasFocus) {
270 
271        /* When focus is lost check that the text field
272         * has valid values.
273         */
274        if (!hasFocus) {
275            validateInput(v);
276        }
277    }
278 
279    private void validateInput(View v) {
280        String str = String.valueOf(((TextView) v).getText());
281        if(str.length() == 2 && mFormatter == THREE_DIGIT_FORMATTER)
282                str = str + "0";
283        else if(str.length() == 1 && mFormatter == THREE_DIGIT_FORMATTER)
284                str = str + "00";
285        
286        if ("".equals(str)) {
287 
288            // Restore to the old value as we don't allow empty values
289            updateView();
290        } else {
291 
292            // Check the new value and ensure it's in range
293            validateCurrentView(str);
294        }
295    }
296 
297    /**
298     * We start the long click here but rely on the {@link NumberPickerButton}
299     * to inform us when the long click has ended.
300     */
301    public boolean onLongClick(View v) {
302 
303        /* The text view may still have focus so clear it's focus which will
304         * trigger the on focus changed and any typed values to be pulled.
305         */
306        mText.clearFocus();
307 
308        if (R.id.increment == v.getId()) {
309            mIncrement = true;
310            mHandler.post(mRunnable);
311        } else if (R.id.decrement == v.getId()) {
312            mDecrement = true;
313            mHandler.post(mRunnable);
314        }
315        return true;
316    }
317 
318    public void cancelIncrement() {
319        mIncrement = false;
320    }
321 
322    public void cancelDecrement() {
323        mDecrement = false;
324    }
325 
326    private static final char[] DIGIT_CHARACTERS = new char[] {
327        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
328    };
329 
330    private NumberPickerButton mIncrementButton;
331    private NumberPickerButton mDecrementButton;
332 
333    private class NumberPickerInputFilter implements InputFilter {
334        @SuppressLint("DefaultLocale")
335                public CharSequence filter(CharSequence source, int start, int end,
336                Spanned dest, int dstart, int dend) {
337            if (mDisplayedValues == null) {
338                return mNumberInputFilter.filter(source, start, end, dest, dstart, dend);
339            }
340            CharSequence filtered = String.valueOf(source.subSequence(start, end));
341            String result = String.valueOf(dest.subSequence(0, dstart))
342                    + filtered
343                    + dest.subSequence(dend, dest.length());
344            String str = String.valueOf(result).toLowerCase();
345            for (String val : mDisplayedValues) {
346                val = val.toLowerCase();
347                if (val.startsWith(str)) {
348                    return filtered;
349                }
350            }
351            return "";
352        }
353    }
354 
355    private class NumberRangeKeyListener extends NumberKeyListener {
356 
357        // XXX This doesn't allow for range limits when controlled by a
358        // soft input method!
359        public int getInputType() {
360            return InputType.TYPE_CLASS_NUMBER;
361        }
362 
363        @Override
364        protected char[] getAcceptedChars() {
365            return DIGIT_CHARACTERS;
366        }
367 
368        @Override
369        public CharSequence filter(CharSequence source, int start, int end,
370                Spanned dest, int dstart, int dend) {
371 
372            CharSequence filtered = super.filter(source, start, end, dest, dstart, dend);
373            if (filtered == null) {
374                filtered = source.subSequence(start, end);
375            }
376 
377            String result = String.valueOf(dest.subSequence(0, dstart))
378                    + filtered
379                    + dest.subSequence(dend, dest.length());
380 
381            if ("".equals(result)) {
382                return result;
383            }
384            int val = getSelectedPos(result);
385 
386            /* Ensure the user can't type in a value greater
387             * than the max allowed. We have to allow less than min
388             * as the user might want to delete some numbers
389             * and then type a new number.
390             */
391            if (val > mEnd) {
392                return "";
393            } else {
394                return filtered;
395            }
396        }
397    }
398 
399    @SuppressLint("DefaultLocale")
400        private int getSelectedPos(String str) {
401        if (mDisplayedValues == null) {
402            return Integer.parseInt(str);
403        } else {
404            for (int i = 0; i < mDisplayedValues.length; i++) {
405 
406                /* Don't force the user to type in jan when ja will do */
407                str = str.toLowerCase();
408                if (mDisplayedValues[i].toLowerCase().startsWith(str)) {
409                    return mStart + i;
410                }
411            }
412 
413            /* The user might have typed in a number into the month field i.e.
414             * 10 instead of OCT so support that too.
415             */
416            try {
417                return Integer.parseInt(str);
418            } catch (NumberFormatException e) {
419 
420                /* Ignore as if it's not a number we don't care */
421            }
422        }
423        return mStart;
424    }
425 
426    /**
427     * @return the current value.
428     */
429    public int getCurrent() {
430        return mCurrent;
431    }
432    
433    public String getCurrentFormatted() {
434            return formatNumber(mCurrent);
435    }
436}

[all classes][net.mandaria.tippytipper.widgets]
EMMA 2.0.5312 (C) Vladimir Roubtsov